home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / plan / src / lock.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  7KB  |  273 lines

  1. /*
  2.  * read the master list from the ~/.schedule file. This file is also
  3.  * linked into the daemon program (file_w.c is not).
  4.  *
  5.  *    resolve_tilde(path)        return path with ~ replaced with home
  6.  *                    directory as found in $HOME
  7.  *    find_file(buf, name,exec)    find file <name> and store the path
  8.  *                    in <buf>. Return FALSE if not found.
  9.  *    startup_lock(fname, force)    make sure program runs only once 
  10.  *                    at any time
  11.  *    lockfile(fp, lock)        lock or unlock the database to
  12.  *                    prevent simultaneous access
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include <sys/types.h>
  19. #if defined(IBM) || defined(ULTRIX)
  20. #include <fcntl.h>
  21. #else
  22. #include <sys/fcntl.h>
  23. #endif
  24. #include <pwd.h>
  25. #ifndef MIPS
  26. #include <stdlib.h>
  27. #endif
  28. #if !defined(NOLOCK) && defined(LOCKF) || defined(linux)
  29. #include <sys/file.h>
  30. #endif
  31. #include <unistd.h>
  32. #if !defined(NOLOCK) && defined(LOCKF)
  33. #include <sys/file.h>
  34. #endif
  35. #if defined(IBM) && !defined(NOLOCK)
  36. #include <sys/lockf.h>
  37. #endif
  38. #include <sys/signal.h>
  39. #include "conf.h"
  40.  
  41. #ifdef MIPS
  42. extern char *getenv();
  43. extern struct passwd *getpwnam();
  44. #endif
  45.  
  46. extern char    *progname;    /* argv[0] */
  47. char        lockpath[256];    /* lockfile path */
  48.  
  49.  
  50. /*
  51.  * If <path> begins with a tilde, replace the tilde with $HOME. This is used
  52.  * for the database files, and the holiday file (see holiday.c).
  53.  */
  54.  
  55. char *resolve_tilde(path)
  56.     char        *path;            /* path with ~ */
  57. {
  58.     struct passwd    *pw;            /* for searching home dirs */
  59.     static char    pathbuf[512];        /* path with ~ expanded */
  60.     char        *p, *q;            /* username copy pointers */
  61.     char        *home = 0;        /* home dir (if ~ in path) */
  62.  
  63.     if (*path != '~')
  64.         return(path);
  65.  
  66.     if (!path[1] || path[1] == '/') {
  67.         *pathbuf = 0;
  68.         if (!(home = getenv("HOME")))
  69.             home = getenv("home");
  70.     } else {
  71.         for (p=path+1, q=pathbuf; *p && *p != '/'; p++, q++)
  72.             *q = *p;
  73.         *q = 0;
  74.         if (pw = getpwnam(pathbuf))
  75.             home = pw->pw_dir;
  76.     }
  77.     if (!home) {
  78.         fprintf(stderr, "%s: can't evaluate ~%s in %s, using .\n",
  79.                         progname, pathbuf, path);
  80.         home = ".";
  81.     }
  82.     sprintf(pathbuf, "%s/%s", home, path+1);
  83.     return(pathbuf);
  84. }
  85.  
  86.  
  87. /*
  88.  * locate a program or file, and return its complete path. This is used by
  89.  * the daemon to locate notifier and user programs, and by plan to locate
  90.  * pland and plan.help. Assume that <buf> has space for 1024 chars. PATH
  91.  * is a macro defined by the Makefile.
  92.  */
  93.  
  94. #ifndef PATH
  95. #define PATH 0
  96. #endif
  97. #define DEFAULTPATH "/usr/local/bin:/usr/local/lib:/bin:/usr/bin:/usr/sbin:/usr/ucb:/usr/bsd:/usr/bin/X11:."
  98.  
  99. BOOL find_file(buf, name, exec)
  100.     char            *buf;        /* buffer for returned path */
  101.     char            *name;        /* file name to locate */
  102.     BOOL            exec;        /* must be executable? */
  103. {
  104.     int            method;        /* search path counter */
  105.     char            *path;        /* $PATH or DEFAULTPATH */
  106.     int            namelen;    /* len of tail of name */
  107.     register char        *p, *q;        /* string copy pointers */
  108.  
  109.     if (*name == '/') {                /* begins with / */
  110.         strcpy(buf, name);
  111.         return(TRUE);
  112.     }
  113.     if (*name == '~') {                 /* begins with ~ */
  114.         strcpy(buf, resolve_tilde(name));
  115.         return(TRUE);
  116.     }
  117.     namelen = strlen(name);
  118.     for (method=0; ; method++) {    
  119.         switch(method) {
  120.           case 0:   path = PATH;        break;
  121.           case 1:   path = getenv("PLAN_PATH");    break;
  122.           case 2:   path = getenv("PATH");    break;
  123.           case 3:   path = DEFAULTPATH;        break;
  124.           default:  return(FALSE);
  125.         }
  126.         if (!path)
  127.             continue;
  128.         do {
  129.             q = buf;
  130.             p = path;
  131.             while (*p && *p != ':' && q < buf + 1021 - namelen)
  132.                 *q++ = *p++;
  133.             *q++ = '/';
  134.             strcpy(q, name);
  135.             if (!access(buf, exec ? X_OK : R_OK)) {
  136.                 strcpy(q = buf + strlen(buf), "/..");
  137.                 if (access(buf, X_OK)) {
  138.                     *q = 0;
  139.                     return(TRUE);
  140.                 }
  141.             }
  142.             *buf = 0;
  143.             path = p+1;
  144.         } while (*p);
  145.     }
  146.     /*NOTREACHED*/
  147. }
  148.  
  149.  
  150. /*
  151.  * Make sure that the program is running only once, by creating a special
  152.  * lockfile that contains our pid. If such a lockfile already exists, see
  153.  * if the process that created it exists; if no, ignore it. If <force> is
  154.  * TRUE, try to kill it. Otherwise, return FALSE.
  155.  */
  156.  
  157. BOOL startup_lock(pathtmp, force)
  158.     char            *pathtmp;    /* LOCK_PATH or PLAN_PATH */
  159.     BOOL            force;        /* kill competitor */
  160. {
  161.     char            buf[80];    /* lockfile contents */
  162.     int            lockfd;        /* lock/pid file */
  163.     PID_T            pid;        /* pid in lockfile */
  164.     int            retry = 5;    /* try to kill daemon 5 times*/
  165.  
  166.     sprintf(lockpath, pathtmp, (int)getuid());
  167.     while ((lockfd = open(lockpath, O_WRONLY|O_EXCL|O_CREAT, 0644)) < 0) {
  168.         if ((lockfd = open(lockpath, O_RDONLY)) < 0) {
  169.             int err = errno;
  170.             fprintf(stderr, "%s: cannot open lockfile ", progname);
  171.             errno = err;
  172.             perror(lockpath);
  173.             _exit(1);
  174.         }
  175.         if (read(lockfd, buf, 10) < 5) {
  176.             int err = errno;
  177.             fprintf(stderr, "%s: cannot read lockfile ", progname);
  178.             errno = err;
  179.             perror(lockpath);
  180.             _exit(1);
  181.         }
  182.         buf[10] = 0;
  183.         pid = atoi(buf);
  184.         close(lockfd);
  185.         if (!retry--) {
  186.             fprintf(stderr,
  187.                 "%s: failed to kill process %d owning lockfile %s",
  188.                         progname, pid, lockpath);
  189.             _exit(1);
  190.         }
  191. #        ifndef NOKILL0
  192.         if (kill(pid, 0) && errno == ESRCH) {
  193.             if (unlink(lockpath) && errno != ENOENT) {
  194.                 int err = errno;
  195.                 fprintf(stderr, "%s: cannot unlink lockfile ",
  196.                                 progname);
  197.                 errno = err;
  198.                 perror(lockpath);
  199.                 _exit(1);
  200.             }
  201.             continue;
  202.         }
  203. #        endif
  204.         if (!force)
  205.             return(FALSE);
  206.         (void)kill(pid, SIGINT);
  207.         sleep(1);
  208.     }
  209.     sprintf(buf, "%5d      (pid of lockfile for %s, for user %d)\n",
  210.                 (int)getpid(), progname, (int)getuid());
  211.     if (write(lockfd, buf, strlen(buf)) != strlen(buf)) {
  212.         int err = errno;
  213.         fprintf(stderr, "%s: cannot write lockfile ", progname);
  214.         errno = err;
  215.         perror(lockpath);
  216.         _exit(1);
  217.     }
  218.     close(lockfd);
  219.     return(TRUE);
  220. }
  221.  
  222.  
  223. /*
  224.  * try to lock or unlock the database file. There is actually little risk
  225.  * that two plan programs try to access simultaneously, unless someone adds
  226.  * an appointment graphically, and then another one on the command line
  227.  * within 10 seconds. If people add two at the same time, locking doesn't
  228.  * help at all. As a side effect, the file is rewound.
  229.  */
  230.  
  231. static BOOL got_alarm;
  232. static void (*old_alarm)();
  233. /*ARGSUSED*/ static void alarmhand(sig)
  234. {
  235.     got_alarm = TRUE;
  236.     signal(SIGALRM, old_alarm);
  237. }
  238.  
  239.  
  240. lockfile(fp, lock)
  241.     FILE        *fp;        /* file to lock */
  242.     BOOL        lock;        /* TRUE=lock, FALSE=unlock */
  243. {
  244. #ifndef NOLOCK
  245.     if (lock) {
  246.         got_alarm = FALSE;
  247.         old_alarm = signal(SIGALRM, alarmhand);
  248.         alarm(3);
  249.         (void)rewind(fp);
  250.         (void)lseek(fileno(fp), 0, 0);
  251. #ifdef FLOCK
  252.         if (flock(fileno(fp), LOCK_EX | LOCK_NB) || got_alarm) {
  253. #else
  254.         if (lockf(fileno(fp), F_LOCK, 0) || got_alarm) {
  255. #endif
  256.             perror(progname);
  257.             fprintf(stderr,
  258. "%s: failed to lock database after 3 seconds, accessing anyway\n", progname);
  259.         }
  260.         alarm(0);
  261.     } else {
  262.         (void)rewind(fp);
  263.         (void)lseek(fileno(fp), 0, 0);
  264. #ifdef FLOCK
  265.         (void)flock(fileno(fp), LOCK_UN);
  266. #else
  267.         (void)lockf(fileno(fp), F_ULOCK, 0);
  268. #endif
  269.         return;
  270.     }
  271. #endif /* NOLOCK */
  272. }
  273.